﻿// -----------------------------------------------------------------------
// <copyright file="Parser.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace parser
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class Parser
    {
        Scanner.Token currentToken;
        public bool Experation()
        {
            bool result = this.SimpleExp();

            while (result == true && (currentToken.TokenType == Scanner.TokenType.Equal || currentToken.TokenType == Scanner.TokenType.LessThan))
            {
                result = this.ComparisonOper();
                if (result == true)
                {
                    result = this.SimpleExp();
                }
            }
            return result;
        }

        private bool ComparisonOper()
        {
            bool result;
            if (currentToken.TokenType == Scanner.TokenType.LessThan)
            {
                result = this.Match(Scanner.TokenType.LessThan);
            }
            else if (currentToken.TokenType == Scanner.TokenType.Equal)
            {
                result = this.Match(Scanner.TokenType.Equal);
            }
            else
            {
                return Reject();
            }

            return result;
        }

        private bool SimpleExp()
        {
            bool result = this.Term();
            while (result == true && (currentToken.TokenType == Scanner.TokenType.Plus || currentToken.TokenType == Scanner.TokenType.Minus))
            {
                result = this.AddOper();
                if (result == true)
                {
                    result = this.Term();
                }
            }
            return result;
        }

        private bool AddOper()
        {
            bool result;
            if (this.currentToken.TokenType == Scanner.TokenType.Minus)
            {
                result = this.Match(Scanner.TokenType.Minus);
            }
            else if (this.currentToken.TokenType == Scanner.TokenType.Plus)
            {
                result = this.Match(Scanner.TokenType.Plus);
            }
            else
            {
                return Reject();
            }
            return result;
        }
        public bool Term()
        {
            bool result = this.Factor();
            while (result == true && currentToken.TokenType == Scanner.TokenType.Times)
            {
                result = Match(Scanner.TokenType.Times);
                if (result == true)
                {
                    result = this.Factor();
                }
            }
            return result;
        }

        private bool Factor()
        {
            bool result;
            switch (currentToken.TokenType)
            {
                case Scanner.TokenType.LeftParentheses:
                    {
                        result = this.Match(Scanner.TokenType.LeftParentheses);
                        if (result == true)
                        {
                            result = this.Experation();
                            if (result == true)
                            {
                                result = this.Match(Scanner.TokenType.RightParentheses);
                            }
                        }
                    }
                    break;
                case Scanner.TokenType.Num:
                    {
                        result = this.Match(Scanner.TokenType.Num);
                    }
                    break;
                case Scanner.TokenType.ID:
                    {
                        result = this.Match(Scanner.TokenType.ID);
                    }
                    break;
                default:
                    {
                        return this.Reject();
                    }
            }

            return result;
        }
        public bool Match(Scanner.TokenType s)
        {
            if (currentToken.TokenType == s)
            {
                this.currentToken = this.myScanner.GetNextToken();
                return this.Accept();
            }
            else
            {
                return this.Reject();
            }
        }

        private bool Accept()
        {
            return true;
        }
        public bool parse(Scanner.Scanner newScanner)
        {
            this.myScanner = newScanner;
            currentToken = newScanner.GetNextToken();
            bool result = this.Start();
            if (currentToken.TokenType == Scanner.TokenType.EndFile && result == true)
            {
                return Accept();
            }
            else
            {
                return Reject();
            }
        }

        public bool Start()
        {
            return this.StmtSequence();
        }

        private bool StmtSequence()
        {
            bool result = false;
            result = this.Statement();
            if (result == true)
            {
                while (currentToken.TokenType == Scanner.TokenType.SemiColon)
                {
                    result = this.Match(Scanner.TokenType.SemiColon);
                    if (result == true)
                    {
                        result = this.Statement();
                    }
                    else
                        break;
                }
            }
            return result;
        }

        private bool Statement()
        {
            if (currentToken.TokenType == Scanner.TokenType.Write)
            {
                return this.WriteStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.Read)
            {
                return this.ReadStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.Repeat)
            {
                return this.RepeatStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.If)
            {
                return this.IfStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.ID)
            {
                return this.AssignStmt();
            }
            else
            {
                return this.Reject();
            }
        }

        private bool AssignStmt()
        {
            bool result = this.Match(Scanner.TokenType.ID);
            if (result == true)
            {
                result = this.Match(Scanner.TokenType.Assign);
                if (result == true)
                {
                    result = this.Experation();
                }
            }
            return result;
        }
        private bool IfStmt()
        {
            bool result = this.Match(Scanner.TokenType.If);
            if (result == true)
            {
                result = this.Experation();
                if (result == true)
                {
                    result = this.Match(Scanner.TokenType.Then);
                    if (result == true)
                    {
                        result = this.StmtSequence();
                        switch (this.currentToken.TokenType)
                        {
                            case Scanner.TokenType.End:
                                {
                                    result = this.Match(Scanner.TokenType.End);
                                }
                                break;
                            case Scanner.TokenType.Else:
                                {
                                    result = this.Match(Scanner.TokenType.Else);
                                    if (result == true)
                                    {
                                        result = this.StmtSequence();
                                        if (result == true)
                                        {
                                            result = this.Match(Scanner.TokenType.End);
                                        }
                                    }
                                }
                                break;
                            default:
                                {
                                    return this.Reject();
                                }
                        }
                        return result;
                    }
                }
            }

            return result;
        }
        private bool RepeatStmt()
        {
            bool result = this.Match(Scanner.TokenType.Repeat);
            if (result == true)
            {
                result = this.StmtSequence();
                if (result == true)
                {
                    result = this.Match(Scanner.TokenType.Until);
                    if (result == true)
                    {
                        result = this.Experation();
                    }
                }
            }

            return result;
        }
        private bool ReadStmt()
        {
            bool result = this.Match(Scanner.TokenType.Read);
            if (result == true)
            {
                result = this.Match(Scanner.TokenType.ID);
            }

            return result;
        }

        private bool WriteStmt()
        {
            bool result = this.Match(Scanner.TokenType.Write);
            if (result == true)
            {
                result = this.Experation();
            }

            return result;
        }

        private bool Reject()
        {
            return false;
        }

        public Scanner.Scanner myScanner { get; set; }
    }
}
